package com.quanyan.assets.service.impl;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.quanyan.api.APIRequest;
import com.quanyan.api.APIResponse;
import com.quanyan.api.enums.ApiResponseEnum;
import com.quanyan.api.enums.AssetsType;
import com.quanyan.assets.emun.AssetsErrorEnum;
import com.quanyan.assets.entity.*;
import com.quanyan.assets.enums.ActivityCouponType;
import com.quanyan.assets.enums.CouponOrderType;
import com.quanyan.assets.enums.CouponStatus;
import com.quanyan.assets.enums.SportType;
import com.quanyan.assets.mapper.CouponMapper;
import com.quanyan.assets.mapper.ETbUserAssetsMapper;
import com.quanyan.assets.mapper.TbCouponInfoMapper;
import com.quanyan.assets.mapper.TbCouponMapper;
import com.quanyan.assets.repository.UserAssetsRepository;
import com.quanyan.assets.request.ReqCoupon;
import com.quanyan.assets.response.RespCoupon;
import com.quanyan.assets.response.RespOrderCoupon;
import com.quanyan.assets.service.CouponService;
import com.quanyan.assets.service.UtilCouponService;
import com.quanyan.common.Plugin.PageObj;
import com.quanyan.common.enums.BaseEnum;
import com.quanyan.common.exception.BizException;
import com.quanyan.common.utils.StringUtil;
import com.quanyan.common.utils.ValidationResult;
import com.quanyan.common.utils.ValidationUtils;
import com.quanyan.common.utils.VersionUtils;
import com.quanyan.common.vo.resp.RespCity;
import com.quanyan.place.client.PlaceClient;
import com.quanyan.place.response.PlaceBaseResponse;
import com.quanyan.user.serviceFacade.UserServiceFacade;

import java.text.ParseException;
import java.util.regex.*;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by wmb on 2016/10/13.
 */
@Service("couponService")
public class CouponServiceImpl implements CouponService{
    private static Logger logger = LoggerFactory.getLogger(CouponServiceImpl.class);

    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private TbCouponMapper tbCouponMapper;
    @Autowired
    private TbCouponInfoMapper tbCouponInfoMapper;
    @Autowired
    private ETbUserAssetsMapper eTbUserAssetsMapper;
    @Autowired
    private UserAssetsRepository userAssetsRepository;
    @Autowired
    private UserServiceFacade userServiceFacade;
    @Autowired
    private PlaceClient placeClient;
    @Autowired
    private UtilCouponService utilCouponService;


    @Override
    @Valid
    //获取已领取的优惠券列表
    public APIResponse<RespOrderCoupon> getReceiveCouponList(APIRequest<ReqCoupon> apiRequest) {
        String reqVer = apiRequest.getVer();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy.MM.dd");
        ReqCoupon reqCoupon=apiRequest.getData();
        TbCouponInfoExample tbCouponInfoExample=new TbCouponInfoExample();
        TbCouponInfoExample.Criteria criteria= tbCouponInfoExample.createCriteria();
        criteria.andUidEqualTo(reqCoupon.getUid());
        if(reqCoupon.getStatus().equals(CouponStatus.RECEIVE.id.byteValue())){
            //获取已领取列表
            List<Byte> statusList=new ArrayList<Byte>();
            statusList.add(reqCoupon.getStatus());
            statusList.add(CouponStatus.DISABLE.id.byteValue());
            criteria.andStatusIn(statusList);
            int count=tbCouponInfoMapper.countByExample(tbCouponInfoExample);
            reqCoupon.setPageNo(reqCoupon.getPageNo()*reqCoupon.getPageSize());
            List<RespCoupon> couponList=couponMapper.getReceiveCouponList(reqCoupon);
            for(RespCoupon respCoupon:couponList){
                respCoupon.setUseTime(sdf.format(respCoupon.getValidBeginDate()) + "-" + sdf.format(respCoupon.getValidEndDate()));
                makeUseRule(respCoupon, reqCoupon, true, reqVer);
            }
            PageObj<List<RespCoupon>> pageObj = PageObj.create(count, reqCoupon.getPageNo() / reqCoupon.getPageSize(), reqCoupon.getPageSize(), couponList);
            //可用优惠券列表
            tbCouponInfoExample.clear();
            criteria= tbCouponInfoExample.createCriteria();
            criteria.andUidEqualTo(reqCoupon.getUid());
            criteria.andStatusEqualTo(CouponStatus.RECEIVE.id.byteValue());
            int usecount=tbCouponInfoMapper.countByExample(tbCouponInfoExample);
            RespOrderCoupon respOrderCoupon = new RespOrderCoupon();
            respOrderCoupon.setPageObj(pageObj);
            respOrderCoupon.setUseAmount(usecount);
            return APIResponse.returnSuccess(respOrderCoupon);
        }else if(reqCoupon.getStatus().equals(CouponStatus.EXPIRED.id.byteValue())){
            //获取失效列表
            criteria.andStatusEqualTo(CouponStatus.EXPIRED.id.byteValue());
            int count=tbCouponInfoMapper.countByExample(tbCouponInfoExample);
            reqCoupon.setPageNo(reqCoupon.getPageNo() * reqCoupon.getPageSize());
            List<RespCoupon> couponList=couponMapper.getExpiredCouponList(reqCoupon);
            for(RespCoupon respCoupon:couponList){
                respCoupon.setUseTime(sdf.format(respCoupon.getValidBeginDate()) +"-"+sdf.format(respCoupon.getValidEndDate()));

                makeUseRule(respCoupon, reqCoupon, true, reqVer);
            }
            PageObj<List<RespCoupon>> pageObj=PageObj.create(count,reqCoupon.getPageNo()/reqCoupon.getPageSize(),reqCoupon.getPageSize(),couponList);
            RespOrderCoupon respOrderCoupon=new RespOrderCoupon();
            respOrderCoupon.setPageObj(pageObj);
            return APIResponse.returnSuccess(respOrderCoupon);
        }
        return null;
    }

    @Override
    @Valid
    //获取订单使用的优惠券列表
    public APIResponse<RespOrderCoupon> getOrderCouponList(APIRequest<ReqCoupon> apiRequest) {
        String reqVer = apiRequest.getVer();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy.MM.dd");
        ReqCoupon reqCoupon=apiRequest.getData();
        reqCoupon.setStatus(CouponStatus.RECEIVE.id.byteValue());
        //参数校验
        getOrderCouponListValid(reqCoupon);
        TbCouponInfoExample tbCouponInfoExample=new TbCouponInfoExample();
        TbCouponInfoExample.Criteria criteria= tbCouponInfoExample.createCriteria();
        criteria.andUidEqualTo(reqCoupon.getUid());
        if(reqCoupon.getStatus().equals(CouponStatus.RECEIVE.id.byteValue())){
            //获取已领取列表
            List<Byte> statusList=new ArrayList<Byte>();
            statusList.add(reqCoupon.getStatus());
            statusList.add(CouponStatus.DISABLE.id.byteValue());
            criteria.andStatusIn(statusList);
            int count=tbCouponInfoMapper.countByExample(tbCouponInfoExample);
            reqCoupon.setPageNo(reqCoupon.getPageNo()*reqCoupon.getPageSize());

            Date nowTime = new Date();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(nowTime);
            calendar.add(Calendar.DATE, -1);

            List<RespCoupon> couponList=couponMapper.getOrderCouponList(reqCoupon, nowTime,calendar.getTime());
            couponList = resetUsedByTimeLimit(couponList, reqCoupon, reqVer);

            for(RespCoupon respCoupon:couponList){
                respCoupon.setUseTime(sdf.format(respCoupon.getValidBeginDate()) +"-"+sdf.format(respCoupon.getValidEndDate()));
                makeUseRule(respCoupon, reqCoupon, respCoupon.isUsed(), reqVer);
            }
            PageObj<List<RespCoupon>> pageObj=PageObj.create(count,reqCoupon.getPageNo()/reqCoupon.getPageSize(),reqCoupon.getPageSize(),couponList);
            RespOrderCoupon respOrderCoupon=new RespOrderCoupon();
            respOrderCoupon.setPageObj(pageObj);
            //可用优惠券列表
            List<RespCoupon> usedCouponList = getUsedFromAll(couponList);

            if(usedCouponList.isEmpty()){
                respOrderCoupon.setMaxUseMoney(new BigDecimal(0));
                respOrderCoupon.setUseAmount(0);
            }else{
                int useAmount = usedCouponList.size();
                BigDecimal maxUseMoney = new BigDecimal(-1);
                String couponCode = "";
                for (RespCoupon respCoupon : usedCouponList) {
                    BigDecimal couponAmount = null;
                    if (respCoupon.getCouponType() == null || respCoupon.getCouponType() == 1) {
                        couponAmount = respCoupon.getCouponAmount();
                    } else if (respCoupon.getCouponType() == 2) {// 折扣券
                        couponAmount = reqCoupon.getEnabledAmount().multiply(new BigDecimal(1.0).subtract(respCoupon.getDiscount().divide(new BigDecimal(10))));// 优惠金额
                        Long topDiscountAmount = respCoupon.getTopDiscountAmount();
                        if (topDiscountAmount != null && topDiscountAmount != -1 && topDiscountAmount - couponAmount.doubleValue() < 0) {
                            couponAmount = new BigDecimal(topDiscountAmount);
                        }
                        if (reqVer != null && VersionUtils.compareVersion(reqVer, "2.7") < 0) { // 2.7版本之前的折扣券都不能使用
                            useAmount--;
                            couponAmount = new BigDecimal(-2);
                        }
                    }
                    if (maxUseMoney.compareTo(couponAmount) < 0) {
                        maxUseMoney = couponAmount;
                        couponCode = respCoupon.getCouponCode();
                    }
                }
                maxUseMoney = maxUseMoney.setScale(1, BigDecimal.ROUND_FLOOR);
                respOrderCoupon.setMaxUseMoney(maxUseMoney);
                respOrderCoupon.setUseAmount(useAmount);
                respOrderCoupon.setCouponCode(couponCode);
            }
            return APIResponse.returnSuccess(respOrderCoupon);
        }
        return null;
    }

    private boolean validateByAppVer(String limitWeekday, String limitTime, String appVer) {
        if ((!StringUtils.isBlank(limitTime) || !StringUtils.isBlank(limitTime))
                && appVer != null && VersionUtils.compareVersion(appVer, "2.7.3") < 0) {
            return false;
        }

        return true;
    }

    private List<RespCoupon> resetUsedByTimeLimit(List<RespCoupon> allCoupon, ReqCoupon reqCoupon, String reqVer) {
        List<RespCoupon> result = Lists.newArrayList();

        for (RespCoupon respCoupon : allCoupon) {
            //限时间段优惠券限制只能用于2.7.3以上版本
            if (!validateByAppVer(respCoupon.getLimitWeekday(), respCoupon.getLimitTime(), reqVer)) {
                respCoupon.setUsed(false);
            }
            //如果优惠券根据使用时间限制为不可用，则设置used=false
            if (!validatePlaceTimeLimit(respCoupon, reqCoupon)) {
                respCoupon.setUsed(false);
            }
            result.add(respCoupon);
        }

        Collections.sort(result, new Comparator<RespCoupon>() {
            @Override
            public int compare(RespCoupon o1, RespCoupon o2) {
                if (!o1.getStatus().equals(o2.getStatus())) {
                    return o1.getStatus().compareTo(o2.getStatus());
                }

                if (o1.isUsed() != o2.isUsed()) {
                    if (o1.isUsed()) {
                        return -1; //未使用的优惠券排在前面
                    } else {
                        return 1;
                    }
                }

                //自然顺序逆序，金额大的排在前面
                return (-1) * o1.getCouponAmount().compareTo(o2.getCouponAmount());
            }
        });

        return result;
    }

    private  List<RespCoupon> getUsedFromAll(List<RespCoupon> allCoupon) {
        List<RespCoupon> result = Lists.newArrayList();

        for (RespCoupon respCoupon : allCoupon) {
            if (respCoupon.isUsed())
                result.add(respCoupon);
        }

        return result;
    }

    private boolean validatePlaceTimeLimit(RespCoupon curCoupon, ReqCoupon reqData) {
        List<String> placeOrderTimeList = reqData.getPlaceDateTimeList();
        String limitWeekdayList = curCoupon.getLimitWeekday();
        String limitTimeRange = curCoupon.getLimitTime();

        CouponLimit couponLimit = CouponLimit.parse(limitWeekdayList, limitTimeRange);
        if (placeOrderTimeList == null) {
            return true;
        }
        for (String placeOrderTime : placeOrderTimeList) {
            if (!PlaceOrderTime.parse(placeOrderTime).matchCouponLimit(couponLimit)) {
                return false;
            }
        }

        return true;
    }

    private void makeUseRule(RespCoupon respCoupon, ReqCoupon reqCoupon, boolean tag, String reqVer) {
        List<String> useRule = new ArrayList<String>();
        if(respCoupon.getStatus().equals(CouponStatus.DISABLE.id.byteValue())){
            //停用
            useRule.add("该券已被系统停用，有疑问可咨询百灵鸟客服4008-706-616");
        } else if (reqVer != null && VersionUtils.compareVersion(reqVer, "2.7") < 0 && respCoupon.getCouponType() == 2) { // 2.7版本之前的折扣券都不能使用
            respCoupon.setUsed(false);
            useRule.add("限百灵鸟2.7.3及以上版本使用");
        } else if (!validateByAppVer(respCoupon.getLimitWeekday(), respCoupon.getLimitTime(), reqVer)) {
            respCoupon.setUsed(false);
            useRule.add("限百灵鸟2.7.3及以上版本使用");
        } else {
            if(tag) {//是否显示为可使用
                //订单类型
                if("0".equals(respCoupon.getOrderType()) //订单类型
                        && "0".equals(respCoupon.getSportType()) //运动方式
                        && "0".equals(respCoupon.getCity()) //城市
                        && "0".equals(respCoupon.getPlaceIds()) //场馆编号
                        && "0".equals(reqCoupon.getPaymethod()) //支付方式
                        && "".equals(respCoupon.getLimitWeekday()) //限周几使用
                        && "".equals(respCoupon.getLimitTime()) //限时间段使用
                        ){
                    useRule.add("全场通用");
                }else{
                    if(null!=respCoupon.getOrderType()&&!respCoupon.getOrderType().equals("0")){
                        String[] orderTypeList=respCoupon.getOrderType().split(",");
                        String orderUseRule = "";
                        for(String str:orderTypeList){
                            if(null!= CouponOrderType.getById(Integer.parseInt(str))){
                                orderUseRule += CouponOrderType.getNameById(Integer.parseInt(str))+"、";
                            }
                        }
                        if(orderUseRule.length() > 0) {
                            orderUseRule = orderUseRule.substring(0, orderUseRule.length() - 1);
                            useRule.add("限" + orderUseRule +"订单使用");
                        }
                    }
                    if (null!=respCoupon.getSportType()&&!respCoupon.getSportType().equals("0")){
                        String[] sportTypeList=respCoupon.getSportType().split(",");
                        String sportUseRule = "";
                        for(String str:sportTypeList){
                            if(null!= SportType.getById(Integer.parseInt(str))) {
                                sportUseRule += SportType.getNameById(Integer.parseInt(str)) + "、";
                            }
                        }
                        if(sportUseRule.length() > 0) {
                            sportUseRule = sportUseRule.substring(0, sportUseRule.length() - 1);
                            useRule.add("限" + sportUseRule + "项目使用");
                        }
                    }
                    if (null != respCoupon.getCity() && !"0".equals(respCoupon.getCity())) {
                        String[] cityList = respCoupon.getCity().split(",");
                        String sportUseRule = "";
                        for(String str : cityList) {
                            String cityName = getCityNameByCityId(Integer.parseInt(str));
                            if (StringUtil.isNotBlank(cityName)) {
                                sportUseRule += cityName + "、";
                            }
                        }
                        if(sportUseRule.length()>0) {
                            sportUseRule = sportUseRule.substring(0, sportUseRule.length() - 1);
                            useRule.add("限" + sportUseRule +"地区使用");
                        }
                    }

                    if (null != respCoupon.getPlaceIds() && !"0".equals(respCoupon.getPlaceIds())) {
                        String[] placeList = respCoupon.getPlaceIds().split(",");
                        String placeUseRule = "";
                        for(String str : placeList) {
                            String placeName = getPlaceNameByPlaceId(Integer.parseInt(str));
                            if (StringUtil.isNotBlank(placeName)) {
                                placeUseRule += placeName + "、";
                            }
                        }
                        if(placeUseRule.length()>0) {
                            placeUseRule = placeUseRule.substring(0, placeUseRule.length() - 1);
                            useRule.add("限于" + placeUseRule +"使用");
                        }
                    }
                    if (null != respCoupon.getPaymethod() && !"0".equals(respCoupon.getPaymethod())) {
                        Byte payMethod = respCoupon.getPaymethod();
                        if (payMethod == 1) {
                            useRule.add("限场馆会员卡支付使用");
                        } else if (payMethod == 2) {
                            useRule.add("限非场馆会员卡支付使用");
                        }
                    }

                    CouponLimit couponLimit
                            = CouponLimit.parse(respCoupon.getLimitWeekday(), respCoupon.getLimitTime());

                    if (null != respCoupon.getLimitWeekday() && !"".equals(respCoupon.getLimitWeekday())) {
                        String rule = couponLimit.makeWeekdayRule();
                        if (rule != null) {
                            useRule.add(rule);
                        }
                    }
                    if (null != respCoupon.getLimitTime() && !"".equals(respCoupon.getLimitTime())) {
                        String rule = couponLimit.makeTimeRangeRule();
                        if (rule != null) {
                            useRule.add(rule);
                        }
                    }
                }
            } else {

                //不可使用
                if (new Date().getTime() < respCoupon.getValidBeginDate().getTime()) {
                    useRule.add("优惠券未开始生效");
                }

                //订单未满
                if (reqCoupon.getEnabledAmount().compareTo(respCoupon.getEnabledAmount()) < 0) {
                    useRule.add("金额未满" + respCoupon.getEnabledAmount() + "元");
                }

                //订单类型不可用
                if(null!=respCoupon.getOrderType()&&!respCoupon.getOrderType().equals("0")){
                    String[] orderTypeList=respCoupon.getOrderType().split(",");
                    if(!Arrays.asList(orderTypeList).contains(reqCoupon.getOrderType().toString())){
                        String orderUseRule = "";
                        for(String str:orderTypeList){
                            if(null!=CouponOrderType.getById(Integer.parseInt(str))){
                                orderUseRule += CouponOrderType.getNameById(Integer.parseInt(str)) + "、";
                            }
                        }
                        if(orderUseRule.length() > 0) {
                            orderUseRule = orderUseRule.substring(0, orderUseRule.length()-1);
                            useRule.add("限" + orderUseRule + "订单使用");
                        }
                    }
                }
                //运动类型不可用
                if (null!=respCoupon.getSportType()&&!respCoupon.getSportType().equals("0")){
                    String[] sportTypeList=respCoupon.getSportType().split(",");
                    if(!Arrays.asList(sportTypeList).contains(reqCoupon.getSportType().toString())) {
                        String sportUseRule = "";
                        for(String str:sportTypeList){
                            if(null!=SportType.getById(Integer.parseInt(str))) {
                                sportUseRule += SportType.getNameById(Integer.parseInt(str)) + "、";
                            }
                        }
                        if(sportUseRule.length() > 0) {
                            sportUseRule = sportUseRule.substring(0, sportUseRule.length() - 1);
                            useRule.add("限" + sportUseRule +"项目使用");
                        }
                    }
                }

                // 城市不可用
                if (null != respCoupon.getCity() && !respCoupon.getCity().equals("0")) {
                    String[] cityList = respCoupon.getCity().split(",");
                    if(!Arrays.asList(cityList).contains(""+reqCoupon.getCityId())) {
                        String placeUseRule = "";
                        for(String str : cityList) {
                            String cityName = getCityNameByCityId(Integer.parseInt(str));
                            if (StringUtil.isNotBlank(cityName)) {
                                placeUseRule += cityName + "、";
                            }
                        }
                        if(placeUseRule.length() > 0) {
                            placeUseRule = placeUseRule.substring(0, placeUseRule.length() - 1);
                            useRule.add("限" + placeUseRule +"地区使用");
                        }
                    }
                }

                // 场馆不可用
                if (null != respCoupon.getPlaceIds() && !"0".equals(respCoupon.getPlaceIds())) {
                    String[] placeList = respCoupon.getPlaceIds().split(",");
                    if(!Arrays.asList(placeList).contains(""+reqCoupon.getPlaceId())) {
                        String sportUseRule = "";
                        for(String str : placeList) {
                            String placeName = getPlaceNameByPlaceId(Integer.parseInt(str));
                            if (StringUtil.isNotBlank(placeName)) {
                                sportUseRule += placeName + "、";
                            }
                        }
                        if(sportUseRule.length() > 0) {
                            sportUseRule = sportUseRule.substring(0, sportUseRule.length() - 1);
                            useRule.add("限于" + sportUseRule +"使用");
                        }
                    }
                }

                // 支付方式不可用
                if (null != respCoupon.getPaymethod() && !"0".equals(respCoupon.getPaymethod())) {
                    Byte payMethod = respCoupon.getPaymethod();
                    if (payMethod != reqCoupon.getPaymethod()) {
                        if (payMethod == 1) {
                            useRule.add("限场馆会员卡支付使用");
                        } else if (payMethod == 2) {
                            useRule.add("限非场馆会员卡支付使用");
                        }
                    }
                }

                CouponLimit couponLimit
                        = CouponLimit.parse(respCoupon.getLimitWeekday(), respCoupon.getLimitTime());
                boolean weekdayRuleAdded = false;
                boolean timeRuleAdded = false;
                if (reqCoupon.getPlaceDateTimeList() != null) {
                    for (String orderTime : reqCoupon.getPlaceDateTimeList()) {
                        PlaceOrderTime placeOrderTime = PlaceOrderTime.parse(orderTime);
                        if (!weekdayRuleAdded && !placeOrderTime.matchCouponWeekdayLimit(couponLimit)) {
                            String rule = couponLimit.makeWeekdayRule();
                            if (rule != null) {
                                useRule.add(rule);
                            }
                            weekdayRuleAdded = true;
                        }
                        if (!timeRuleAdded && !placeOrderTime.matchCouponTimeLimit(couponLimit)) {
                            String rule = couponLimit.makeTimeRangeRule();
                            if (rule != null) {
                                useRule.add(rule);
                            }
                            timeRuleAdded = true;
                        }
                    }
                }
            }
        }
        respCoupon.setUseRule(useRule);

        // 设置折扣文字
        Byte couponType = respCoupon.getCouponType();
        String discountText = "";
        if (couponType == null || couponType == 1) { // 代金券
            discountText = "￥" + respCoupon.getCouponAmount();
        } else if (couponType == 2) { // 折扣券
            discountText = respCoupon.getDiscount() + "折";
        }
        respCoupon.setDiscountText(discountText);
    }

    private String getPlaceNameByPlaceId(int placeId) {
        String name = "";
        try {
            PlaceBaseResponse placeBaseResponse = placeClient.getPlaceById(placeId);
            if (placeBaseResponse != null) {
                name = placeBaseResponse.getName();
            }
        } catch (Exception e) {
            logger.error("调用场馆接口，根据城市ID获取地址信息出错。", e);
        }
        return name;
    }

    private String getCityNameByCityId(Integer cityId) {
        APIResponse<RespCity> response = userServiceFacade.getCity(cityId);
        String name = "";
        if (response != null && response.isRet()) {
            name = response.getData().getName();
        }
        return name;
    }


    private void getOrderCouponListValid(ReqCoupon reqCoupon) {
        if(null==reqCoupon.getOrderType()){
            throw new BizException(AssetsErrorEnum.ORDER_TYPE_IS_NULL);
        }
        if(null==reqCoupon.getSportType()){
            throw new BizException(AssetsErrorEnum.SPORT_TYPE_IS_NULL);
        }
        if (null == reqCoupon.getCityId()) {
            throw new BizException(AssetsErrorEnum.CITY_ID_IS_NULL);
        }
        if(null==reqCoupon.getEnabledAmount()){
            throw new BizException(AssetsErrorEnum.ENABLED_AMOUNT_IS_NULL);
        }
        if (null == reqCoupon.getPlaceId()) {
            reqCoupon.setPlaceId(0);
        }
        if (null == reqCoupon.getPaymethod()) {
            reqCoupon.setPaymethod((byte) 2);//普通支付
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
    @Valid
    public APIResponse<RespCoupon> freezeCoupon(APIRequest<ReqCoupon> apiRequest) {
        ReqCoupon reqCoupon=apiRequest.getData();
        //参数校验
        freezeCouponValid(reqCoupon);
        Date nowTime = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowTime);
        calendar.add(Calendar.DATE, -1);
        //冻结优惠券
        int count=couponMapper.freezeByCode(reqCoupon, nowTime,calendar.getTime());
        if(count==1){
            //更新资产表
            int updateAssets=eTbUserAssetsMapper.updateFreezeCoupon(reqCoupon.getUid(), AssetsType.ASSETS_COUPON.id.byteValue());
            //获取优惠券信息
            RespCoupon respCoupon = couponMapper.selectInfoByCode(reqCoupon.getCouponCode());
            Byte couponType = respCoupon.getCouponType();
            BigDecimal discount = respCoupon.getDiscount();
            Long topDiscountAmount = respCoupon.getTopDiscountAmount();

            //校验优惠券使用时间
            CouponLimit couponLimit = CouponLimit.parse(respCoupon.getLimitWeekday(), respCoupon.getLimitTime());
            if (reqCoupon.getPlaceDateTimeList() != null) {
                for (String orderTime : reqCoupon.getPlaceDateTimeList()) {
                    PlaceOrderTime placeOrderTime = PlaceOrderTime.parse(orderTime);
                    if (!placeOrderTime.matchCouponLimit(couponLimit)) {
                        throw new BizException(AssetsErrorEnum.ILLEGAL_COUPON_USE_TIME);
                    }
                }
            }

            if (couponType == null || couponType == 1) { // 代金券
                if(reqCoupon.getCouponAmount() == null || respCoupon.getCouponAmount().compareTo(reqCoupon.getCouponAmount()) < 0){
                    throw new BizException(AssetsErrorEnum.COUPON_AMOUNT_IS_VALID);
                }
            } else if (couponType == 2) { // 折扣券
                if (discount == null || discount.compareTo(BigDecimal.ZERO) < 0 || discount.compareTo(new BigDecimal(10)) > 0) {
                    throw new BizException(AssetsErrorEnum.ILLEGAL_COUPON_DISCOUNT);
                }
                BigDecimal discountAmount = reqCoupon.getEnabledAmount().multiply(new BigDecimal(1.0).subtract(discount.divide(new BigDecimal(10))));// 优惠金额
                if (discountAmount.compareTo(reqCoupon.getCouponAmount()) < 0) {
                    throw new BizException(AssetsErrorEnum.COUPON_AMOUNT_IS_VALID);
                }
                if (topDiscountAmount != -1 && topDiscountAmount - reqCoupon.getCouponAmount().doubleValue() < 0) {
                    throw new BizException(AssetsErrorEnum.COUPON_AMOUNT_IS_VALID);
                }
            } else {
                throw new BizException(AssetsErrorEnum.ILLEGAL_COUPON_TYPE);
            }
            return APIResponse.returnSuccess(respCoupon);
        }else if(count==0){
            //之前已经冻结
            TbCouponInfoExample tbCouponInfoExample=new TbCouponInfoExample();
            TbCouponInfoExample.Criteria criteria=tbCouponInfoExample.createCriteria();
            criteria.andStatusEqualTo(CouponStatus.FREEZE.id.byteValue());
            criteria.andSystemCodeEqualTo(reqCoupon.getSystemCode());
            criteria.andBusinessCodeEqualTo(reqCoupon.getBusinessCode());
            criteria.andOrderNoEqualTo(reqCoupon.getOrderNo());
            List<TbCouponInfo> tbCouponInfoList=tbCouponInfoMapper.selectByExample(tbCouponInfoExample);
            if(tbCouponInfoList.isEmpty()){
                throw new BizException(AssetsErrorEnum.VALID_USE_COUPON);
            }else{
                //获取优惠券信息
                RespCoupon respCoupon=couponMapper.selectInfoByCode(reqCoupon.getCouponCode());
                return APIResponse.returnSuccess(respCoupon);
            }

        }
        return null;
    }

    @Override
    @Valid
    @Transactional(rollbackFor = Exception.class)
    public APIResponse<TbUserAssets> unfreezeCouponSuccess(APIRequest<ReqCoupon> apiRequest) {
        ReqCoupon reqCoupon=apiRequest.getData();
        //参数校验
        unfreezeCouponValid(reqCoupon);
        //解冻优惠券（成功）
        reqCoupon.setStatus(CouponStatus.USED.id.byteValue());
        reqCoupon.setOrderState((byte) 11); // 已支付
        //解冻完成
        return unfreezeComplate(reqCoupon);
    }

    @Override
    @Valid
    @Transactional(rollbackFor = Exception.class)
    public APIResponse<TbUserAssets> unfreezeCouponFail(APIRequest<ReqCoupon> apiRequest) {
        ReqCoupon reqCoupon=apiRequest.getData();
        //参数校验
        unfreezeCouponValid(reqCoupon);
        //解冻优惠券（失败）
        reqCoupon.setStatus(CouponStatus.RECEIVE.id.byteValue());
        //解冻完成
        return unfreezeComplate(reqCoupon);
    }

    @Override
    @Valid
    @Transactional(rollbackFor = Exception.class)
    public APIResponse<BaseEnum> associateUsers(APIRequest<ReqCoupon> apiRequest) {
        ReqCoupon reqCoupon=apiRequest.getData();
        //参数校验
        associateUsersValid(reqCoupon);
        int count=couponMapper.associateUsers(reqCoupon);
        return APIResponse.returnSuccess();
    }

    @Override
    @Valid
    public APIResponse<RespCoupon> getInfoByCode(String couponCode) {
        if(null==couponCode){
            throw new BizException(AssetsErrorEnum.COUPON_CODE_IS_NULL);
        }
        RespCoupon respCoupon=couponMapper.selectInfoByCode(couponCode);
        return APIResponse.returnSuccess(respCoupon);
    }

    @Override
    @Valid
    public APIResponse<CouponInfoVo> obtainCoupons(ObtainCouponsParamsVo paramsVo) {
        ValidationResult result = ValidationUtils.validateEntity(paramsVo);
        if (result.hasErrors()) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID, result.getErrorDesc());
        }
        Integer uid = paramsVo.getUid();
        ActivityCouponType activityCouponType = paramsVo.getActivityCouponType();
        String couponTemplateCode = getCouponTemplateCodeByActivityCouponType(activityCouponType);
        if (StringUtil.isBlankOrNull(couponTemplateCode)) {
            return APIResponse.returnFail("后台还未配置该活动优惠券。activityCouponType desc : " + activityCouponType.desc);
        }
        return utilCouponService.obtainCoupons(couponTemplateCode, uid);
    }

    private String getCouponTemplateCodeByActivityCouponType(ActivityCouponType activityCouponType) {
        String auditId = activityCouponType.getSearchFlag();

        TbCouponExample example = new TbCouponExample();
        TbCouponExample.Criteria criteria = example.createCriteria();
        criteria.andAuditIdEqualTo(auditId);

        List<TbCoupon> couponList = tbCouponMapper.selectByExample(example);
        String couponTemplateCode = "";
        if (couponList.size() > 0) {
            couponTemplateCode = couponList.get(couponList.size()-1).getCouponId();
        }
        return couponTemplateCode;
    }

    private void associateUsersValid(ReqCoupon reqCoupon) {
        if(null==reqCoupon.getUid()){
            throw new BizException(AssetsErrorEnum.USER_ID_NULL);
        }
        if(null==reqCoupon.getMobile()){
            throw new BizException(AssetsErrorEnum.MOBILE_IS_NULL);
        }
    }

    private APIResponse<TbUserAssets> unfreezeComplate(ReqCoupon reqCoupon) {
        TbCouponInfoExample tbCouponInfoExample=new TbCouponInfoExample();
        TbCouponInfoExample.Criteria criteria=tbCouponInfoExample.createCriteria();
        criteria.andCouponCodeEqualTo(reqCoupon.getCouponCode());
        List<TbCouponInfo> couponInfoList=tbCouponInfoMapper.selectByExample(tbCouponInfoExample);
        int count=couponMapper.unfreezeComplate(reqCoupon);
        if(count==1){
            reqCoupon.setUid(couponInfoList.get(0).getUid());
            eTbUserAssetsMapper.updateUnfreezeCoupon(reqCoupon);
            TbUserAssets tbUserAssets = userAssetsRepository.selectByUidAndAssetsType(couponInfoList.get(0).getUid(), AssetsType.ASSETS_COUPON.id.byteValue());
            return APIResponse.returnSuccess(tbUserAssets);
        }else if(count==0){
            tbCouponInfoExample.clear();
            criteria=tbCouponInfoExample.createCriteria();
            criteria.andCouponCodeEqualTo(reqCoupon.getCouponCode());
            criteria.andStatusEqualTo(reqCoupon.getStatus());
            //校验是否已经解冻过了
            List<TbCouponInfo> checkList=tbCouponInfoMapper.selectByExample(tbCouponInfoExample);
            if(!checkList.isEmpty()){
                TbUserAssets tbUserAssets = userAssetsRepository.selectByUidAndAssetsType(couponInfoList.get(0).getUid(), AssetsType.ASSETS_COUPON.id.byteValue());
                return APIResponse.returnSuccess(tbUserAssets);
            }else{
                throw new BizException(AssetsErrorEnum.UNFREEZE_IS_INVALID);
            }
        }else{
            throw new BizException(AssetsErrorEnum.UNFREEZE_NOT_ONLY);
        }
    }

    private void unfreezeCouponValid(ReqCoupon reqCoupon) {
        if(null== reqCoupon.getCouponCode()){
            throw new BizException(AssetsErrorEnum.COUPON_CODE_IS_NULL);
        }
    }

    private void freezeCouponValid(ReqCoupon reqCoupon) {
        if(null==reqCoupon.getCouponCode()){
            throw new BizException(AssetsErrorEnum.COUPON_CODE_IS_NULL);
        }
        if(null==reqCoupon.getEnabledAmount()){
            throw new BizException(AssetsErrorEnum.ENABLED_AMOUNT_IS_NULL);
        }
        if(null==reqCoupon.getUid()){
            throw new BizException(AssetsErrorEnum.USER_ID_NULL);
        }
        if(null==reqCoupon.getSportType()){
            throw new BizException(AssetsErrorEnum.SPORT_TYPE_IS_NULL);
        }
        if(null==reqCoupon.getOrderType()){
            throw new BizException(AssetsErrorEnum.ORDER_TYPE_IS_NULL);
        }
        if(null==reqCoupon.getOrderNo()){
            throw new BizException(AssetsErrorEnum.ORDER_NO_IS_NULL);
        }
    }


    private static class PlaceOrderTime {
        Integer weekday;
        String beginTime;
        String endTime;

        private static PlaceOrderTime parse(String beginEndTimeStr) {
            PlaceOrderTime result = new PlaceOrderTime();
            Pattern p = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}),(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})");
            Matcher m = p.matcher(beginEndTimeStr);
            if (m.find()) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    Date date = sdf.parse(m.group(1));
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(date);
                    // Calendar里面Sunday是1，Monday是2，所以要减1
                    result.weekday = cal.get(Calendar.DAY_OF_WEEK);
                    if (result.weekday == 1) {
                        result.weekday = 7;
                    } else {
                        result.weekday -= 1;
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                result.beginTime = m.group(2);
                result.endTime = m.group(4);
                if (result.endTime.equals("00:00")) {
                    result.endTime = "24:00";
                }
            } else {
                throw new IllegalArgumentException("场馆时间参数不正确，使用如下格式:\n2017-04-17 18:00,2017-04-17 20:00");
            }

            return result;
        }

        private boolean matchCouponLimit(CouponLimit couponLimit) {
            return matchCouponWeekdayLimit(couponLimit) && matchCouponTimeLimit(couponLimit);
        }

        private boolean matchCouponWeekdayLimit(CouponLimit couponLimit) {
            return couponLimit.limitWeekDay.contains(weekday);
        }

        private boolean matchCouponTimeLimit(CouponLimit couponLimit) {
            return couponLimit.limitBeginTime.compareTo(beginTime) <= 0
                    && couponLimit.limitEndTime.compareTo(endTime) >= 0;
        }
    }

    private static class CouponLimit {
        List<Integer> limitWeekDay = new ArrayList<>();
        String limitBeginTime;
        String limitEndTime;
        private final static String UNLIMITED_TIME_STR = "00:00,24:00";

        private static CouponLimit parse(String limitWeekday, String limitTime) {
            CouponLimit result = new CouponLimit();

            if (limitWeekday == null || limitWeekday.equals("")) {
                limitWeekday = "1,2,3,4,5,6,7";
            }
            String[] splitWeekday = limitWeekday.split(",");
            for (String s : splitWeekday) {
                result.limitWeekDay.add(Integer.valueOf(s));
            }
            if (limitTime == null || limitTime.equals("")) {
                limitTime = UNLIMITED_TIME_STR;
            }

            String[] splitTimeRange = limitTime.split(",");
            if (splitTimeRange[0].length() == 4) {
                splitTimeRange[0] = "0" + splitTimeRange[0];
            }
            if (splitTimeRange[1].length() == 4) {
                splitTimeRange[1] = "0" + splitTimeRange[1];
            }
            result.limitBeginTime = splitTimeRange[0];
            result.limitEndTime = splitTimeRange[1];
            if (result.limitEndTime.equals("00:00")) {
                result.limitEndTime = "24:00";
            }

            return result;
        }

        //如果返回null，表示没有限制
        private String makeWeekdayRule() {
            Collections.sort(limitWeekDay);
            if (limitWeekDay.size() == 7) {
                return null;
            }

            List<String> ruleStringList = new ArrayList<>();
            Deque<Integer> seqWeekday = new ArrayDeque<>();
            for (int day : limitWeekDay) {
                if (seqWeekday.size() == 0) {
                    seqWeekday.push(day);
                    continue;
                }
                if (seqWeekday.size() > 0) {
                    if ((seqWeekday.peekFirst() + 1) == day) {
                        seqWeekday.push(day);
                    } else {
                        addSeqWeekdayToRuleList(seqWeekday, ruleStringList);
                        seqWeekday.push(day);
                    }
                }
            }

            addSeqWeekdayToRuleList(seqWeekday, ruleStringList);

            return "限用于" + Joiner.on("、").join(ruleStringList) + "的场地";
        }

        //如果返回null，表示没有限制
        private void addSeqWeekdayToRuleList(Deque<Integer> seqWeekday, List<String> ruleStringList) {
            final List<String> weekdayDescList = Lists.newArrayList("", "周一", "周二", "周三", "周四", "周五", "周六", "周日");
            if (seqWeekday.size() >= 3) {
                ruleStringList.add(weekdayDescList.get(seqWeekday.getLast()) + "至" + weekdayDescList.get(seqWeekday.getFirst()));
            } else if (seqWeekday.size() == 2) {
                ruleStringList.add(weekdayDescList.get(seqWeekday.removeLast()) + "、" + weekdayDescList.get(seqWeekday.removeLast()));
            } else {
                ruleStringList.add(weekdayDescList.get(seqWeekday.removeLast()) + "");
            }
            seqWeekday.clear();
        }

        private String makeTimeRangeRule() {
            String timeRange = limitBeginTime + "-" + limitEndTime;
            if (timeRange.equals("00:00-24:00")) {
                return null;
            }

            return "限用于" + timeRange + "时间段场地";
        }
    }

    /*public static void main(String[] args) {
//        PlaceOrderTime pot = PlaceOrderTime.parse("\"2017-04-14 08:00,2017-04-17 10:00\",\"2017-04-14 18:00,2017-04-17 20:00\"");
//        System.out.println(pot);

        CouponLimit couponLimit = CouponLimit.parse("5,6,7,3,1", "08:00,20:00");
        System.out.println(couponLimit.makeWeekdayRule());
        System.out.println(couponLimit.makeTimeRangeRule());
    }*/

}
